<template>
  <div class="vb-select" :class="{ row: isColLayout }">
    <label v-if="labelText" :class="labelClass">
      {{ labelText }}
    </label>
    <div class="vb-select-content" :class="contentClass">
      <div
        class="vb-select-main form-control d-flex flex-row justify-content-center align-items-center"
        ref="selectMain"
        :class="{ 'vb-select-multiple': multiple && selectedItems.length > 0, 'vb-select-readonly': !editable }"
        @click="onClickSelect"
      >
        <div class="vb-select-items flex-fill">
          <template v-if="multiple">
            <span
              class="badge bg-light text-dark border border-1"
              v-for="item in selectedItems"
              :key="item.value"
              :style="{ height: inputHeight ? inputHeight + 'px' : '' }"
            >
              <span>{{ item.text }}</span>
              <button type="button" class="btn-close" @click="removeItem($event, item)"></button>
            </span>
          </template>
          <span class="vb-select-items-input" :style="{ width: inputWidth }">
            <input
              type="text"
              :placeholder="(multiple && selectedItems.length > 0) || !editable ? '' : placeholder"
              @keydown="keydown"
              @focus="onFocus"
              :readonly="!editable"
              v-model="inputValue"
              @input="onInput"
            />
          </span>
        </div>
        <div class="vb-select-icon">
          <i :class="['bi-chevron-' + (listgroupVisible ? 'up' : 'down')]"></i>
        </div>
        <div
          class="list-group shadow"
          v-show="listgroupVisible"
          :style="{ top: top, bottom: bottom, 'max-height': listMaxHeight }"
          ref="listgroupEl"
        >
          <slot name="noData" v-if="listgroupData.length === 0">
            <div class="bg-white text-center p-4 text-muted">
              <div class="mb-2">
                <i class="bi bi-clipboard fs-2"></i>
              </div>
              暂无数据
            </div>
          </slot>
          <a
            v-for="(el, i) in listgroupData"
            :key="el.value"
            href="javascript:void(0)"
            @click="onClickItem(el)"
            class="list-group-item list-group-item-action"
            :class="{ active: el.selected, 'vb-pre-select': i === preSelIndex && !el.selected }"
          >
            {{ el.text }}
          </a>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import { computed, defineComponent, nextTick, onMounted, ref, SetupContext, watch } from "vue";
import { SelectCommon, SelectDataItem } from "./select.type";
import { UPDATE_MODEL_EVENT, INPUT_EVENT } from "../../utils/constants";

import { CommonUtil } from "../../utils";
import SelectedItems from "./selectedItems";
import ListgroupOper from "./listgroupOper";
import InputOper from "./inputOper";
export default defineComponent({
  emits: [UPDATE_MODEL_EVENT, INPUT_EVENT],
  name: "VbSelect",
  props: {
    placeholder: { type: String, default: "" },
    editable: { type: Boolean, default: false },
    multiple: { type: Boolean, default: false },
    data: {
      type: Array,
      default() {
        return [];
      },
    },
    isColLayout: { type: Boolean, default: true },
    colCls: { type: String, default: "" },
    //col-xx-2 col-2 col
    labelColSize: { type: Number, default: 2 },
    //col-xx-10 col-10 col
    contentColSize: { type: Number, default: 10 },
    labelText: { type: String, default: "" },
    modelValue: {
      type: [Array, String, Number],
      default() {
        return [];
      },
    },
    listMaxHeight: { type: String, default: "300px" },
    filterData: { type: [Function, Boolean], default: true },
    //当multiple和editable为true时生效
    resetAfterSelect: { type: Boolean, default: false },
  },
  setup(props: any, ctx: SetupContext) {
    const inputValue = ref<string | number>("");
    const selectedItems = SelectedItems(ctx);
    const selectMain = ref<HTMLDivElement>();
    //各模块公共对象
    const common: SelectCommon = {
      selectedItems,
      inputValue,
      selectMain,
      listgroupOper: null,
    };
    const listgroupOper = ListgroupOper(props, common);
    common.listgroupOper = listgroupOper;
    const inputOper = InputOper(props, ctx, common);
    const labelClass = computed(() => {
      if (props.isColLayout) {
        return `col-form-label ${CommonUtil.getColClass({ colCls: props.colCls, colSize: props.labelColSize })}`;
      } else {
        return "form-label";
      }
    });
    const contentClass = computed(() => {
      if (props.isColLayout) {
        return `${CommonUtil.getColClass({ colCls: props.colCls, colSize: props.contentColSize })}`;
      } else {
        return "";
      }
    });
    watch(
      () => props.modelValue,
      (v) => {
        setValue(v);
      }
    );
    watch(
      () => props.data,
      (newData) => {
        newData.forEach((el: SelectDataItem) => {
          const existIndex = selectedItems.exist(el.value);
          if (existIndex !== false) {
            el.selected = true;
            selectedItems.updateItem(existIndex as number, el);
          }
        });
        inputOper.refreshData();
        nextTick(() => {
          //数据有变化 高度也可能会变化
          listgroupOper.resize();
        });
      }
    );
    onMounted(() => {
      if (props.modelValue.length > 0) {
        setValue(props.modelValue);
      }
    });
    function setValue(values: (string | number)[] | null | number | string) {
      if (values === null) {
        values = [];
      } else if (!Array.isArray(values)) {
        values = [values];
      }
      const items = selectedItems.ref.value;
      const existValues: (string | number)[] = [];
      items.forEach((item) => {
        if ((values as (string | number)[]).indexOf(item.value) !== -1) {
          existValues.push(item.value);
        }
      });
      if (existValues.length === values.length && values.length !== 0) return;
      const targetItems: SelectDataItem[] = [];
      values.forEach((value) => {
        props.data.forEach((item: SelectDataItem) => {
          if (item.value === value) {
            targetItems.push(item);
            return false;
          }
        });
      });
      selectedItems.set(targetItems);
      if (!props.multiple) {
        inputValue.value = targetItems.length > 0 ? targetItems[0].text : "";
      }
    }
    return {
      inputValue,
      selectMain,
      contentClass,
      labelClass,
      selectedItems: selectedItems.ref,
      listgroupVisible: listgroupOper.visible,
      onClickItem: listgroupOper.onClickItem,
      listgroupData: listgroupOper.data,
      preSelIndex: listgroupOper.preSelIndex,
      top: listgroupOper.top,
      bottom: listgroupOper.bottom,
      listgroupEl: listgroupOper.element,
      ...inputOper,
    };
  },
});
</script>
<style>
.vb-select-main {
  position: relative;
  padding: 0.375rem 0.75rem;
}
.vb-select-readonly,
.vb-select-readonly input {
  background-color: #e9ecef;
  cursor: pointer;
}
.vb-select-readonly .vb-select-items {
  cursor: pointer;
}
.vb-select-multiple {
  padding: 0.1875rem 0.75rem 0.1875rem 0.375rem;
}
.vb-select-multiple .badge {
  margin: 0.1875rem 0.375rem 0.1875rem 0;
  padding: 0;
  padding-left: 0.35em;
}
.vb-select-multiple .vb-select-items-input {
  width: 5px;
}
.vb-select-items {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  cursor: text;
}
.vb-select-items .badge button {
  width: 0.8em;
  height: 0.8em;
  padding: 0.55em;
  border-radius: 0.15em;
}
.vb-select-items > span {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}
.vb-select-items-input input {
  border: 0;
  padding: 0;
  width: 100%;
}
.vb-select-items-input input:focus {
  outline: 0;
}
.vb-select-icon {
  font-size: 0;
}
.vb-select-icon i {
  font-size: 14px;
}
/* list group */
.vb-select-main .list-group {
  position: absolute;
  z-index: 1000;
  overflow: auto;
  margin: 0;
  border: 1px solid #ddd;
  left: 0;
  right: 0;
  top: 100%;
}
.vb-select-main .list-group-item {
  border-left: 0;
  border-right: 0;
}
.vb-select-main .list-group-item:first-child {
  border-radius: 0;
  border-top: 0;
}
.vb-select-main .list-group-item:last-child {
  border-radius: 0;
  border-bottom: 0;
}
.vb-select-main .list-group-item.vb-pre-select {
  background-color: #f5f5f5;
}
</style>
